import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import tkinter.scrolledtext as scrolledtext
import can
from can.interfaces.vector import get_channel_configs, VectorBus
from can.interfaces.vector.xldefine import XL_BusTypes
import isotp
import re
import json
import os
from copy import deepcopy
from Load_HEX import Load_HEX  # 导入 Load_HEX 类
from Precondition import Precondition  # 导入 Precondition 类
import threading
import time
from can.io import BLFWriter, ASCWriter
import datetime

class UDS_BL_UPDATE_GUI:
    def __init__(self, master):
        self.master = master
        master.title("UDS BL Update GUI")

        # 第一行
        self.frame1 = tk.Frame(master)
        self.frame1.pack(fill=tk.X, expand=True, padx=5, pady=5)

        self.vendor_var = tk.StringVar(value="Vector")
        self.vendor_combobox = ttk.Combobox(self.frame1, textvariable=self.vendor_var, values=["Vector", "ZLG"], state="readonly")
        self.vendor_combobox.pack(side=tk.LEFT, padx=5)
        self.vendor_combobox.bind("<<ComboboxSelected>>", self.on_vendor_change)

        self.type_var = tk.StringVar()
        self.type_combobox = ttk.Combobox(self.frame1, textvariable=self.type_var, state="disabled")
        self.type_combobox.pack(side=tk.LEFT, padx=5)
        self.type_combobox.set("Type")

        self.channel_var = tk.StringVar()
        self.channel_combobox = ttk.Combobox(self.frame1, textvariable=self.channel_var, state="readonly", width=30)
        self.channel_combobox.pack(side=tk.LEFT, padx=5)
        self.channel_combobox.set("Channel")

        self.connect_button = ttk.Button(self.frame1, text="Connect", command=self.connect)
        self.connect_button.pack(side=tk.LEFT, padx=5)

        # 列表和文本框
        self.frame3 = tk.Frame(master)
        self.frame3.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        self.listbox_frame = tk.Frame(self.frame3)
        self.listbox_frame.pack(side=tk.LEFT, padx=5, pady=5, fill=tk.Y, expand=True)

        self.listbox_up_frame = tk.Frame(self.listbox_frame)
        self.listbox_up_frame.pack(side=tk.TOP, fill=tk.X, expand=False)

        self.cmd_options = [
            'Physical_Send',
            'Wait(ms)',
            'Functional_Send',
            'TransferDrv_34/36/37',
            'TransferAPP_34/36/37',
            'Unlock',
            'Security_dll',
            'Bitrate(bps)',
            'Physical_ID',
            'Response_ID',
            'Functional_ID',
            'Start_Precondition',
            'Stop_Precondition'
        ]
        self.cmd_var = tk.StringVar()
        self.cmd_combobox = ttk.Combobox(self.listbox_up_frame, textvariable=self.cmd_var, values=self.cmd_options, state="readonly")
        self.cmd_combobox.pack(side=tk.LEFT, padx=5)
        self.cmd_combobox.set(self.cmd_options[0])

        self.data_entry = tk.Entry(self.listbox_up_frame)
        self.data_entry.pack(side=tk.LEFT, padx=5, expand=True, fill=tk.X)

        self.add_button = ttk.Button(self.listbox_up_frame, text="Add", command=self.on_add_button_click)
        self.add_button.pack(padx=5, pady=5)

        self.listbox = tk.Listbox(self.listbox_frame, width=50, height=10)  # 调整宽度和高度
        self.listbox.pack(side=tk.LEFT, fill=tk.Y, expand=True)

        # 添加滚动条（可选）
        scrollbar = ttk.Scrollbar(self.listbox_frame, orient=tk.VERTICAL, command=self.listbox.yview)
        scrollbar.pack(side=tk.LEFT, fill=tk.Y)
        self.listbox.config(yscrollcommand=scrollbar.set)

        self.button_frame = tk.Frame(self.listbox_frame)
        self.button_frame.pack(side=tk.RIGHT, padx=5)

        self.up_button = ttk.Button(self.button_frame, text="Up", command=self.move_item_up)
        self.up_button.pack(pady=2)

        self.down_button = ttk.Button(self.button_frame, text="Down", command=self.move_item_down)
        self.down_button.pack(pady=2)

        self.delete_button = ttk.Button(self.button_frame, text="Delete", command=self.delete_item)
        self.delete_button.pack(pady=2)

        self.save_button = ttk.Button(self.button_frame, text="Save", command=self.save_to_config)
        self.save_button.pack(pady=2)

        self.frame3_right_frame = tk.Frame(self.frame3)
        self.frame3_right_frame.pack(side=tk.RIGHT, padx=5, pady=5, fill=tk.Y, expand=True)

        self.frame3_right_up_frame_0 = ttk.Frame(self.frame3_right_frame)
        self.frame3_right_up_frame_0.pack(side=tk.TOP, padx=5, pady=0, fill=tk.X, expand=True)
        
        self.path_DRV = tk.Text(self.frame3_right_up_frame_0, height=1, state="disabled", wrap="none")
        self.path_DRV.pack(side=tk.LEFT, padx=5, expand=True, fill=tk.X)

        self.load_DRV_button = ttk.Button(self.frame3_right_up_frame_0, text="Load DRV", command=self.load_DRV_file)
        self.load_DRV_button.pack(side=tk.RIGHT, padx=5, pady=5)

        self.frame3_right_up_frame_1 = ttk.Frame(self.frame3_right_frame)
        self.frame3_right_up_frame_1.pack(side=tk.TOP, padx=5, pady=0, fill=tk.X, expand=True)

        self.path_APP = tk.Text(self.frame3_right_up_frame_1, height=1, state="disabled", wrap="none")
        self.path_APP.pack(side=tk.LEFT, padx=5, expand=True, fill=tk.X)

        self.load_APP_button = ttk.Button(self.frame3_right_up_frame_1, text="Load APP", command=self.load_APP_file)
        self.load_APP_button.pack(side=tk.RIGHT, padx=5, pady=5)

        self.frame3_right_up_frame_flash = ttk.Frame(self.frame3_right_frame)
        self.frame3_right_up_frame_flash.pack(side=tk.TOP, padx=5, pady=0, fill=tk.X, expand=True)

        self.flash_frame = tk.Frame(self.frame3_right_up_frame_flash)
        self.flash_frame.pack(fill=tk.X, padx=5, pady=5)

        self.output_text = scrolledtext.ScrolledText(self.frame3_right_frame)
        self.output_text.pack(fill=tk.X, expand=True)

        self.flash_button = ttk.Button(self.flash_frame, text="Flash", command=self.flash_process)
        self.flash_button.pack(pady=0)

        # 复选框和单选按钮
        self.frame4 = tk.Frame(master)
        self.frame4.pack(fill=tk.X, padx=5, pady=5)

        self.log_var = tk.BooleanVar()
        self.log_check = tk.Checkbutton(self.frame4, text="Log", variable=self.log_var)
        self.log_check.pack(side=tk.LEFT, padx=5)

        self.log_format = tk.StringVar(value="BLF")  # 默认选择 BLF 格式
        self.blf_radio = tk.Radiobutton(self.frame4, text="BLF", variable=self.log_format, value="BLF")
        self.blf_radio.pack(side=tk.LEFT, padx=5)

        self.asc_radio = tk.Radiobutton(self.frame4, text="ASC", variable=self.log_format, value="ASC")
        self.asc_radio.pack(side=tk.LEFT, padx=5)

        self.update_vector_channels()

        # 在初始化结束时自动加载配置
        self.load_from_config()

        # ... 其他初始化代码 ...
        self.drv_data = None
        self.app_data = None
        self.bitrate = '500000'
        self.bus = None  # 初始化 bus 属性为 None
        self.precondition = None  # 初始化 precondition 属性为 None
        self.tp_physical = None  # 物理寻址 TP
        self.tp_functional = None  # 功能寻址 TP
        self.physical_id = 0x7E0  # 默认物理地址
        self.response_id = 0x7E8  # 默认接收地址
        self.functional_id = 0x7DF  # 默认功能地址
        self.security_dll_path = None  # 初始化 security_dll 路径为 None
        self.notifier = None

    def on_vendor_change(self, event):
        if self.vendor_var.get() == "Vector":
            self.type_combobox.config(state="disabled")
            self.update_vector_channels()
        else:
            self.type_combobox.config(state="readonly")
            self.channel_combobox.set("Channel")
            self.channel_combobox['values'] = []

    def update_vector_channels(self):
        try:
            channel_configs = get_channel_configs()
            can_channels = [
                f"{config.name} (Index: {config.channel_index})"
                for config in channel_configs
                if hasattr(config, 'bus_params') and 
                   hasattr(config.bus_params, 'bus_type') and
                   config.bus_params.bus_type == XL_BusTypes.XL_BUS_TYPE_CAN
            ]

            if can_channels:
                self.channel_combobox['values'] = can_channels
                self.channel_combobox.set(can_channels[0])
            else:
                self.channel_combobox.set("无可用CAN通道")
                self.channel_combobox['values'] = []
        except Exception as e:
            print(f"获取Vector CAN通道时出错: {str(e)}")
            self.channel_combobox.set("无可用CAN通道")
            self.channel_combobox['values'] = []

    def on_add_button_click(self):
        data = self.data_entry.get().strip()
        cmd = self.cmd_combobox.get()
        if cmd == "Security_dll":
            combined = f"{cmd}: {data}"
            self.listbox.insert(tk.END, combined)
        elif self.is_valid_data(data):
            combined = f"{cmd}: {data}"
            self.listbox.insert(tk.END, combined)
        else:
            messagebox.showerror("输入错误", "请输入有效的数据格式（10进制数、16进制数或空格分隔的16进制字节数组）")

    def is_valid_data(self, data):
        if not data:  # 允许空输入
            return True
        
        # 检查是否为10进制数
        if data.isdigit():
            return True
        
        # 检查是否为16进制数
        if re.match(r'^0x[0-9A-Fa-f]+$', data):
            return True
        
        # 检查是否为空格分隔的16进制字节数组
        hex_bytes = data.split()
        return all(re.match(r'^[0-9A-Fa-f]{2}$', byte) for byte in hex_bytes)

    def move_item_up(self):
        selected_indices = self.listbox.curselection()
        if not selected_indices or selected_indices[0] == 0:
            return  # 没有选中项或选中项已经在顶部

        index = selected_indices[0]
        item = self.listbox.get(index)
        self.listbox.delete(index)
        self.listbox.insert(index - 1, item)
        self.listbox.selection_set(index - 1)

    def move_item_down(self):
        selected_indices = self.listbox.curselection()
        if not selected_indices or selected_indices[0] == self.listbox.size() - 1:
            return  # 没有选中项或选中项已经在底部

        index = selected_indices[0]
        item = self.listbox.get(index)
        self.listbox.delete(index)
        self.listbox.insert(index + 1, item)
        self.listbox.selection_set(index + 1)

    def delete_item(self):
        selected_indices = self.listbox.curselection()
        if not selected_indices:
            return  # 没有选中项

        self.listbox.delete(selected_indices[0])

    def save_to_config(self):
        # 获取 listbox 中的所有项目
        items = self.listbox.get(0, tk.END)
        
        # 创建配置字典
        config = {"items": list(items)}
        
        # 保存到 JSON 文件
        try:
            with open('config.json', 'w') as f:
                json.dump(config, f, indent=4)
            messagebox.showinfo("保存成功", "配置已保存")
        except Exception as e:
            messagebox.showerror("保存失败", f"保存配置时出错：{str(e)}")

    # 可选：添加加载配置的方法
    def load_from_config(self):
        if os.path.exists('config.json'):
            try:
                with open('config.json', 'r') as f:
                    config = json.load(f)
                self.listbox.delete(0, tk.END)  # 清空当前列表
                for item in config.get('items', []):
                    self.listbox.insert(tk.END, item)
                print("配置已从 config.json 加载")  # 使用 print 而不是 messagebox
            except Exception as e:
                print(f"加载配置时出错：{str(e)}")  # 使用 print 而不是 messagebox
        else:
            print("config.json 文件不存在")  # 使用 print 而不是 messagebox

    def load_DRV_file(self):
        filetypes = [
            ('S-Record Files / Hex Files', '*.s* *.hex'),
            ('All Files', '*.*')
        ]
        filename = filedialog.askopenfilename(
            title="选择 DRV 文件",
            filetypes=filetypes,
            initialdir=os.getcwd()  # 设置初始目录为当前工作目录
        )
        
        if filename:
            try:
                hex_loader = Load_HEX()
                hex_loader.load_file(filename)
                self.drv_data = deepcopy(hex_loader.get_data())
                
                self.path_DRV.config(state="normal")
                self.path_DRV.delete("1.0", tk.END)
                self.path_DRV.insert("1.0", filename)
                self.path_DRV.config(state="disabled")
                
                print(f"成功加载并解析DRV文件: {filename}")

            except Exception as e:
                print(f"错误: {str(e)}")
        else:
            print("未选择文件")

    def load_APP_file(self):
        filetypes = [
            ('S-Record Files / Hex Files', '*.s* *.hex'),
            ('All Files', '*.*')
        ]
        filename = filedialog.askopenfilename(
            title="选择 APP 文件",
            filetypes=filetypes,
            initialdir=os.getcwd()  # 设置初始目录为当前工作目录
        )
        
        if filename:
            try:
                hex_loader = Load_HEX()
                hex_loader.load_file(filename)
                self.app_data = deepcopy(hex_loader.get_data())
                
                self.path_APP.config(state="normal")
                self.path_APP.delete("1.0", tk.END)
                self.path_APP.insert("1.0", filename)
                self.path_APP.config(state="disabled")
                
                print(f"成功加载并解析APP文件: {filename}")

            except Exception as e:
                messagebox.showerror("错误", f"无法打开或解析文件: {str(e)}")
        else:
            print("未选择文件")

    def parse_cmd(self, cmd_string):
        # 使用 ": " 分割指令和参数
        parts = cmd_string.split(": ", 1)
        cmd = parts[0]
        param = parts[1] if len(parts) > 1 else ""  # 如果没有参数,则设为空字符串
        
        # 检查指令是否在预定义的 cmd_options 中
        if cmd not in self.cmd_options:
            print(f"未知指令: {cmd}")
            return

        # 根据不同的指令执行相应的任务
        if cmd == 'Physical_Send':
            self.physical_send(param)
        elif cmd == 'Wait(ms)':
            self.wait_ms(param)
        elif cmd == 'Functional_Send':
            self.functional_send(param)
        elif cmd == 'TransferDrv_34/36/37':
            self.transfer_drv(param)
        elif cmd == 'TransferAPP_34/36/37':
            self.transfer_app(param)
        elif cmd == 'Unlock':
            self.unlock(param)
        elif cmd == 'Security_dll':
            self.security_dll(param)
        elif cmd == 'Bitrate(bps)':
            self.set_bitrate(param)
        elif cmd == 'Physical_ID':
            self.set_physical_id(param)
        elif cmd == 'Response_ID':
            self.set_response_id(param)
        elif cmd == 'Functional_ID':
            self.set_functional_id(param)
        elif cmd == 'Start_Precondition':
            self.start_precondition(param)
        elif cmd == 'Stop_Precondition':
            self.stop_precondition(param)
        else:
            print(f"尚未实现的指令: {cmd}")

    # 以下是各个指令对应的方法,现在它们都接受一个可能为空的参数
    def physical_send(self, param):
        if not param:
            self.output_text.insert(tk.END, "错误: Physical_Send 需要参数\n")
            self.output_text.see(tk.END)
            return None
        
        try:
            message = bytes.fromhex(param)
            self.tp_physical.send(message)
            self.output_text.insert(tk.END, f"发送物理寻址消息: {param}\n")
            self.output_text.see(tk.END)
            while self.tp_physical.transmitting():
                time.sleep(0.005)
            
            # 调用接收方法并直接返回结果
            return self.receive_tp_message(self.tp_physical)
        except ValueError:
            self.output_text.insert(tk.END, f"错误: 无效的十六进制字符串 '{param}'\n")
            self.output_text.see(tk.END)
        except Exception as e:
            self.output_text.insert(tk.END, f"发送消息时发生错误: {str(e)}\n")
            self.output_text.see(tk.END)

    def wait_ms(self, param):
        try:
            wait_time = int(param) if param else 0
            self.output_text.insert(tk.END, f"等待 {wait_time} 毫秒\n")
            self.output_text.see(tk.END)
            time.sleep(wait_time / 1000)
        except ValueError:
            self.output_text.insert(tk.END, f"错误: 无效的等待时间参数 '{param}'\n")
            self.output_text.see(tk.END)

    def functional_send(self, param):
        if not param:
            self.output_text.insert(tk.END, "错误: Functional_Send 需要参数\n")
            self.output_text.see(tk.END)
            return None
        
        try:
            message = bytes.fromhex(param)
            self.tp_functional.send(message)
            self.output_text.insert(tk.END, f"发送功能寻址消息: {param}\n")
            self.output_text.see(tk.END)
            while self.tp_functional.transmitting():
                time.sleep(0.005)
            
            # 调用接收方法并直接返回结果
            return self.receive_tp_message(self.tp_physical)
        except ValueError:
            self.output_text.insert(tk.END, f"错误: 无效的十六进制字符串 '{param}'\n")
            self.output_text.see(tk.END)
        except Exception as e:
            self.output_text.insert(tk.END, f"发送消息时发生错误: {str(e)}\n")
            self.output_text.see(tk.END)

    def _transfer_data(self, data_type, param):
        # 将参数字符串转换为字节数组
        param_bytes = bytes.fromhex(param)
        
        if len(param_bytes) != 3:
            self.output_text.insert(tk.END, f"错误: Transfer{data_type}_34 需要3字节参数\n")
            self.output_text.see(tk.END)
            return

        # 解析参数
        service_id = param_bytes[0]  # 服务ID，应该是0x34
        data_format_identifier = param_bytes[1]  # dataFormatIdentifier
        address_length_format_identifier = param_bytes[2]  # addressAndLengthFormatIdentifier

        # 计算地址和长度的字节数
        address_bytes = address_length_format_identifier & 0x0F
        length_bytes = (address_length_format_identifier & 0xF0) >> 4

        # 选择数据源
        data_source = self.drv_data if data_type == "DRV" else self.app_data

        # 遍历所有的数据段
        for segment in data_source:
            # 获取起始地址、长度和数据
            start_address = segment['start_address']
            length = segment['length']
            data = segment['data']

            # 构造34服务请求
            service_34 = bytearray([service_id, data_format_identifier, address_length_format_identifier])
            service_34.extend(start_address.to_bytes(address_bytes, 'big'))
            service_34.extend(length.to_bytes(length_bytes, 'big'))
            
            # 发送34服务请求并接收响应
            response_34 = self.physical_send(service_34.hex().upper())

            if not response_34:
                self.output_text.insert(tk.END, f"错误: 34服务未收到响应 (地址: 0x{start_address:X})\n")
                self.output_text.see(tk.END)
                return

            # 解析lengthFormatIdentifier和maxNumberOfBlockLength
            length_format_identifier = response_34[1]
            max_number_of_block_length_bytes = (length_format_identifier & 0xF0) >> 4
            
            # 解析maxNumberOfBlockLength
            max_block_length = int.from_bytes(response_34[2:2+max_number_of_block_length_bytes], 'big')
            
            self.output_text.insert(tk.END, f"最大块长度: {max_block_length} 字节\n")
            self.output_text.see(tk.END)

            # 发送36服务
            for i in range(0, len(data), max_block_length - 2):
                block = data[i:i+max_block_length-2]
                block_number = (i // (max_block_length - 2)) + 1
                service_36 = bytearray([0x36, block_number])
                service_36.extend(block)
                response_36 = self.physical_send(service_36.hex().upper())

                if not response_36:
                    self.output_text.insert(tk.END, f"错误: 36服务第{block_number}块未收到响应 (地址: 0x{start_address:X})\n")
                    self.output_text.see(tk.END)
                    return

                self.output_text.insert(tk.END, f"36服务第{block_number}块发送成功 (地址: 0x{start_address:X})\n")
                self.output_text.see(tk.END)

            # 发送37服务
            response_37 = self.physical_send(bytes([0x37]))

            if not response_37:
                self.output_text.insert(tk.END, f"错误: 37服务未收到响应 (地址: 0x{start_address:X})\n")
            else:
                self.output_text.insert(tk.END, f"Transfer{data_type}_34/36/37 执行完成 (地址: 0x{start_address:X})\n")
            self.output_text.see(tk.END)

        self.output_text.insert(tk.END, f"所有{data_type}数据段传输完成\n")
        self.output_text.see(tk.END)

    def transfer_drv(self, param):
        self._transfer_data("DRV", param)

    def transfer_app(self, param):
        self._transfer_data("APP", param)

    def unlock(self, param):
        self.output_text.insert(tk.END, f"执行 Unlock: {param if param else '无参数'}\n")
        self.output_text.see(tk.END)

        # 发送解锁请求并获取种子
        seed_response = self.physical_send(f"27{param}")
        if seed_response and len(seed_response) > 2:
            seed = seed_response[2:]  # 从第三个字节开始获取种子
            security_level = int(param, 16)  # 将param转换为16进制整数
            variant = "SomeVariant"  # 示例变体名称

            # 调用 use_security_dll 生成密钥
            key = self.use_security_dll(seed, security_level, variant)

            if key:
                # 发送生成的密钥
                key_message = bytearray([0x27, int(param, 16) + 1])  # 0x27 后面的字节是 param+1
                key_message.extend(key)
                unlock_response = self.physical_send(key_message.hex().upper())

                if unlock_response:
                    self.output_text.insert(tk.END, "解锁成功\n")
                else:
                    self.output_text.insert(tk.END, "解锁失败\n")
            else:
                self.output_text.insert(tk.END, "生成密钥失败\n")
        else:
            self.output_text.insert(tk.END, "获取种子失败\n")
        
        self.output_text.see(tk.END)

    def security_dll(self, param):
        try:
            if param:
                self.security_dll_path = param
                self.output_text.insert(tk.END, f"设置 Security DLL 路径: {self.security_dll_path}\n")
            else:
                self.security_dll_path = None
                self.output_text.insert(tk.END, "清除 Security DLL 路径\n")
        except Exception as e:
            self.output_text.insert(tk.END, f"设置 Security DLL 路径时发生错误: {str(e)}\n")
        self.output_text.see(tk.END)

    def set_bitrate(self, param):
        self.bitrate = param if param else '500000'
        print(f"设置比特率为 {self.bitrate} bps")

    def set_physical_id(self, param):
        try:
            self.physical_id = int(param, 16) if param else 0x7E0
            self.output_text.insert(tk.END, f"设置 Physical_ID: 0x{self.physical_id:X}\n")
        except ValueError:
            self.output_text.insert(tk.END, f"无效的 Physical_ID: {param}\n")
        self.output_text.see(tk.END)

    def set_response_id(self, param):
        try:
            self.response_id = int(param, 16) if param else 0x7E8
            self.output_text.insert(tk.END, f"设置 Response_ID: 0x{self.response_id:X}\n")
        except ValueError:
            self.output_text.insert(tk.END, f"无效的 Response_ID: {param}\n")
        self.output_text.see(tk.END)

    def set_functional_id(self, param):
        try:
            self.functional_id = int(param, 16) if param else 0x7DF
            self.output_text.insert(tk.END, f"设置 Functional_ID: 0x{self.functional_id:X}\n")
        except ValueError:
            self.output_text.insert(tk.END, f"无效的 Functional_ID: {param}\n")
        self.output_text.see(tk.END)

    def start_precondition(self, param):
        if self.bus is None:
            self.output_text.insert(tk.END, "错误: CAN 总线未连接\n")
            self.output_text.see(tk.END)
            return

        if self.precondition is None:
            self.precondition = Precondition(self.bus)
        
        self.precondition.start()
        self.output_text.insert(tk.END, "开始前置条件\n")
        self.output_text.see(tk.END)

    def stop_precondition(self, param):
        if self.precondition:
            self.precondition.stop()
            self.precondition = None
            self.output_text.insert(tk.END, "停止前置条件\n")
            self.output_text.see(tk.END)
        else:
            self.output_text.insert(tk.END, "警告: 没有正在运行的前置条件\n")
            self.output_text.see(tk.END)

    def connect(self):
        # 遍历 listbox 中的所有项目，查找 Bitrate(bps) 设置
        for item in self.listbox.get(0, tk.END):
            if item.startswith("Bitrate(bps):"):
                self.parse_cmd(item)
                break
        
        try:
            channel_str = self.channel_combobox.get()
            channel_index = int(channel_str.split("Index: ")[-1].strip(")"))
            self.bus = VectorBus(channel=channel_index, bitrate=int(self.bitrate), app_name=None)
            self.output_text.insert(tk.END, f"成功连接到 {channel_str}，比特率：{self.bitrate} bps\n")
            self.output_text.see(tk.END)
        except Exception as e:
            self.output_text.insert(tk.END, f"连接失败：{str(e)}\n")
            self.output_text.see(tk.END)
            self.bus = None  # 如果连接失败,将 bus 设置为 None

    def flash_process(self):
        if self.bus is None:
            self.output_text.insert(tk.END, "错误: CAN 总线未连接\n")
            self.output_text.see(tk.END)
            return

        self.flash_button.config(state="disabled")
        threading.Thread(target=self._flash_thread, daemon=True).start()

    def start_logging(self):
        timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        if hasattr(self, 'blf_radio') and self.log_format.get() == "BLF":
            filename = f"can_log_{timestamp}.blf"
            self.can_logger = BLFWriter(filename)
        elif hasattr(self, 'asc_radio') and self.log_format.get() == "ASC":
            filename = f"can_log_{timestamp}.asc"
            self.can_logger = ASCWriter(filename)
        else:
            self.output_text.insert(tk.END, "错误: 未选择有效的日志格式\n")
            self.output_text.see(tk.END)
            return

        #self.bus.set_filters([{"can_id": 0, "can_mask": 0, "extended": False}])  # 记录所有消息
        self.notifier = can.Notifier(self.bus, [self.can_logger])
        self.output_text.insert(tk.END, f"开始记录 CAN 日志到文件: {filename}\n")
        self.output_text.see(tk.END)

    def stop_logging(self):
        if hasattr(self, 'notifier'):
            self.notifier.stop()
            self.notifier = None
        if hasattr(self, 'can_logger'):
            self.can_logger.stop()
            self.can_logger = None
            self.output_text.insert(tk.END, "CAN 日志记录已停止\n")
            self.output_text.see(tk.END)

    def TP_init(self):
        if self.bus is None:
            self.output_text.insert(tk.END, "错误: CAN 总线未连接，无法初始化 TP\n")
            self.output_text.see(tk.END)
            return False

        try:
            # 遍历listbox的值，找到Physical_ID/Response_ID/Functional_ID并解析
            for item in self.listbox.get(0, tk.END):
                if item.startswith(("Physical_ID:", "Response_ID:", "Functional_ID:", "Security_dll:")):
                    self.parse_cmd(item)

            # 创建一个 Notifier
            self.notifier = can.Notifier(self.bus, [])

            # 物理寻址 TP 初始化
            addr_physical = isotp.Address(isotp.AddressingMode.Normal_11bits, rxid=self.response_id, txid=self.physical_id)
            self.tp_physical = isotp.NotifierBasedCanStack(
                bus=self.bus,
                address=addr_physical,
                error_handler=self.isotp_error_handler,
                notifier=self.notifier
            )
            self.tp_physical.params.set('tx_data_min_length', 8)

            # 功能寻址 TP 初始化
            addr_functional = isotp.Address(isotp.AddressingMode.Normal_11bits, rxid=self.response_id, txid=self.functional_id)
            self.tp_functional = isotp.NotifierBasedCanStack(
                bus=self.bus,
                address=addr_functional,
                error_handler=self.isotp_error_handler,
                notifier=self.notifier
            )
            self.tp_functional.params.set('tx_data_min_length', 8)

            # 启动 TP 层
            self.tp_physical.start()
            self.tp_functional.start()

            # 如果日志选项被选中，开始记录日志
            if hasattr(self, 'log_var') and self.log_var.get():
                self.start_logging()

            self.output_text.insert(tk.END, "物理寻址和功能寻址 TP 初始化并启动成功\n")
            self.output_text.see(tk.END)
            return True
        except Exception as e:
            self.output_text.insert(tk.END, f"TP 初始化失败: {str(e)}\n")
            self.output_text.see(tk.END)
            return False

    def isotp_error_handler(self, error):
        self.output_text.insert(tk.END, f"IsoTP 错误: {str(error)}\n")
        self.output_text.see(tk.END)

    def _flash_thread(self):
        try:
            if not self.TP_init():
                return
            
            # 遍历listbox的值，找到Bitrate(bps)/Physical_ID/Response_ID/Functional_ID以外的项并解析
            for item in self.listbox.get(0, tk.END):
                if not item.startswith(("Bitrate(bps):", "Physical_ID:", "Response_ID:", "Functional_ID:", "Security_dll:")):
                    self.parse_cmd(item)

            # 停止记录日志
            if hasattr(self, 'log_var') and self.log_var.get():
                self.stop_logging()

        finally:
            if self.tp_physical:
                self.tp_physical.stop()
                self.output_text.insert(tk.END, "物理寻址 TP 已停止\n")
            if self.tp_functional:
                self.tp_functional.stop()
                self.output_text.insert(tk.END, "功能寻址 TP 已停止\n")
            self.output_text.see(tk.END)
            self.master.after(0, self._enable_flash_button)

    def _enable_flash_button(self):
        self.flash_button.config(state="normal")

    def __del__(self):
        if self.precondition:
            self.precondition.stop()
        if self.notifier:
            self.notifier.stop()
        if self.tp_physical:
            self.tp_physical.stop()
        if self.tp_functional:
            self.tp_functional.stop()
        self.stop_logging()

    def receive_tp_message(self, tp_stack):
        timeout = 1  # 默认超时时间为1秒
        try:
            while True:
                # 接收消息，使用当前的超时时间
                message = tp_stack.recv(timeout=timeout)
                
                if message is None:
                    return None

                # 解析消息
                self.output_text.insert(tk.END, f"接收到消息: {message.hex()}\n")
                self.output_text.see(tk.END)
                
                # 检查是否为0x7f xx 0x78
                if len(message) == 3 and message[0] == 0x7f and message[2] == 0x78:
                    self.output_text.insert(tk.END, "收到请求等待响应，继续等待...\n")
                    self.output_text.see(tk.END)
                    timeout = 5  # 将超时时间设置为5秒
                    continue
                
                return message
        
        except isotp.IsoTpError as e:
            self.output_text.insert(tk.END, f"IsoTP 错误: {str(e)}\n")
            self.output_text.see(tk.END)
            return None
        except Exception as e:
            self.output_text.insert(tk.END, f"接收消息时发生错误: {str(e)}\n")
            self.output_text.see(tk.END)
            return None

    # 使用 security_dll_path 的方法
    def use_security_dll(self, seed, security_level, variant):
        if self.security_dll_path:
            try:
                import ctypes

                # 合成DLL路径并赋值给变量
                dll_path = os.path.join(os.path.dirname(__file__), self.security_dll_path)
                # 加载 DLL
                dll = ctypes.CDLL(dll_path)

                # 定义函数参数类型
                dll.GenerateKeyEx.argtypes = [
                    ctypes.POINTER(ctypes.c_ubyte), ctypes.c_uint,
                    ctypes.c_uint, ctypes.c_char_p,
                    ctypes.POINTER(ctypes.c_ubyte), ctypes.c_uint,
                    ctypes.POINTER(ctypes.c_uint)
                ]
                dll.GenerateKeyEx.restype = ctypes.c_int

                # 准备参数
                seed_array = (ctypes.c_ubyte * len(seed))(*seed)
                max_key_size = 16  # 假设最大密钥长度为16字节
                key_array = (ctypes.c_ubyte * max_key_size)()
                actual_key_size = ctypes.c_uint()

                # 调用函数
                result = dll.GenerateKeyEx(
                    seed_array, len(seed),
                    security_level, variant.encode(),
                    key_array, max_key_size,
                    ctypes.byref(actual_key_size)
                )

                if result == 0:  # KGRE_Ok
                    key = bytes(key_array[:actual_key_size.value])
                    self.output_text.insert(tk.END, f"成功生成密钥: {key.hex()}\n")
                    return key
                else:
                    error_messages = {
                        1: "缓冲区太小",
                        2: "安全级别无效",
                        3: "变体无效",
                        4: "未指定错误"
                    }
                    error_msg = error_messages.get(result, "未知错误")
                    self.output_text.insert(tk.END, f"生成密钥失败: {error_msg}\n")
            except Exception as e:
                self.output_text.insert(tk.END, f"使用 Security DLL 时发生错误: {str(e)}\n")
        else:
            self.output_text.insert(tk.END, "未设置 Security DLL 路径\n")
        self.output_text.see(tk.END)
        return None

if __name__ == "__main__":
    root = tk.Tk()
    gui = UDS_BL_UPDATE_GUI(root)
    root.mainloop()